using CoreManager.Common;
using CoreManager.Models.DTOs;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace CoreManager.Services.Files
{
    /// <summary>
    /// 文件服务实现
    /// </summary>
    public class FileService : IFileService
    {
        private readonly IWebHostEnvironment _environment;
        private readonly IConfiguration _configuration;
        private readonly ILogger<FileService> _logger;
        private readonly string _uploadRootPath;
        private readonly long _maxFileSize;
        private readonly string _fileAccessBaseUrl;

        public FileService(
            IWebHostEnvironment environment,
            IConfiguration configuration,
            ILogger<FileService> logger)
        {
            _environment = environment;
            _configuration = configuration;
            _logger = logger;

            // 从配置读取上传根路径，默认为 wwwroot/uploads
            _uploadRootPath = _configuration.GetValue<string>("FileUpload:RootPath") 
                ?? Path.Combine(_environment.WebRootPath ?? _environment.ContentRootPath, "uploads");
            
            // 从配置读取最大文件大小，默认为 10MB
            _maxFileSize = _configuration.GetValue<long>("FileUpload:MaxFileSize", 10L * 1024 * 1024);
            
            // 文件访问基础URL
            _fileAccessBaseUrl = _configuration.GetValue<string>("FileUpload:AccessBaseUrl") ?? "/uploads";

            // 确保上传根目录存在
            FileHelper.EnsureDirectoryExists(_uploadRootPath);
        }

        /// <summary>
        /// 上传单个文件
        /// </summary>
        public async Task<ApiResponse<FileUploadResultDto>> UploadFileAsync(IFormFile file, FileUploadDto uploadDto)
        {
            try
            {
                // 验证文件
                var validationResult = ValidateFile(file);
                if (!validationResult.success)
                {
                    return ApiResponse<FileUploadResultDto>.Fail(validationResult.message, 400);
                }

                // 生成文件存储路径
                var subDirectory = FileHelper.GenerateDateBasedPath(uploadDto.BusinessType);
                var directoryPath = Path.Combine(_uploadRootPath, subDirectory);
                FileHelper.EnsureDirectoryExists(directoryPath);

                // 生成唯一文件名
                var uniqueFileName = FileHelper.GenerateUniqueFileName(file.FileName);
                var filePath = Path.Combine(directoryPath, uniqueFileName);
                var relativePath = Path.Combine(subDirectory, uniqueFileName).Replace("\\", "/");

                // 保存文件并计算MD5
                string md5;
                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    await file.CopyToAsync(stream);
                    stream.Position = 0;
                    md5 = FileHelper.CalculateMd5(stream);
                }

                // 构建返回结果
                var result = new FileUploadResultDto
                {
                    FileName = uniqueFileName,
                    OriginalFileName = file.FileName,
                    FileSize = file.Length,
                    Extension = Path.GetExtension(file.FileName).ToLowerInvariant(),
                    RelativePath = relativePath,
                    Url = $"{_fileAccessBaseUrl}/{relativePath}",
                    Md5 = md5,
                    UploadTime = DateTime.Now
                };

                _logger.LogInformation("文件上传成功: {FileName} ({FileSize}), 存储路径: {RelativePath}", 
                    file.FileName, FileHelper.FormatFileSize(file.Length), relativePath);

                return ApiResponse<FileUploadResultDto>.Success(result, "文件上传成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件上传失败: {FileName}", file.FileName);
                return ApiResponse<FileUploadResultDto>.Fail("文件上传失败");
            }
        }

        /// <summary>
        /// 上传多个文件
        /// </summary>
        public async Task<ApiResponse<List<FileUploadResultDto>>> UploadFilesAsync(IFormFileCollection files, FileUploadDto uploadDto)
        {
            try
            {
                if (files == null || files.Count == 0)
                {
                    return ApiResponse<List<FileUploadResultDto>>.Fail("请选择要上传的文件", 400);
                }

                var results = new List<FileUploadResultDto>();
                var errors = new List<string>();

                foreach (var file in files)
                {
                    var uploadResult = await UploadFileAsync(file, uploadDto);
                    if (uploadResult.Code == 200 && uploadResult.Data != null)
                    {
                        results.Add(uploadResult.Data);
                    }
                    else
                    {
                        errors.Add($"{file.FileName}: {uploadResult.Message}");
                    }
                }

                if (errors.Any())
                {
                    var errorMessage = $"部分文件上传失败: {string.Join("; ", errors)}";
                    _logger.LogWarning(errorMessage);
                    return ApiResponse<List<FileUploadResultDto>>.Success(results, errorMessage);
                }

                return ApiResponse<List<FileUploadResultDto>>.Success(results, $"成功上传 {results.Count} 个文件");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量文件上传失败");
                return ApiResponse<List<FileUploadResultDto>>.Fail("批量文件上传失败");
            }
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        public async Task<ApiResponse<bool>> DeleteFileAsync(string relativePath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(relativePath))
                {
                    return ApiResponse<bool>.Fail("文件路径不能为空", 400);
                }

                // 防止路径遍历攻击
                if (relativePath.Contains("..") || relativePath.Contains("~"))
                {
                    return ApiResponse<bool>.Fail("无效的文件路径", 400);
                }

                var filePath = Path.Combine(_uploadRootPath, relativePath.Replace("/", "\\"));
                
                if (!File.Exists(filePath))
                {
                    return ApiResponse<bool>.Fail("文件不存在", 404);
                }

                await Task.Run(() => File.Delete(filePath));

                // 清理空目录
                var directory = Path.GetDirectoryName(filePath);
                if (!string.IsNullOrEmpty(directory))
                {
                    FileHelper.CleanupEmptyDirectories(directory);
                }

                _logger.LogInformation("文件删除成功: {RelativePath}", relativePath);
                return ApiResponse<bool>.Success(true, "文件删除成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件删除失败: {RelativePath}", relativePath);
                return ApiResponse<bool>.Fail("文件删除失败");
            }
        }

        /// <summary>
        /// 批量删除文件
        /// </summary>
        public async Task<ApiResponse<bool>> BatchDeleteFilesAsync(List<string> relativePaths)
        {
            try
            {
                if (relativePaths == null || !relativePaths.Any())
                {
                    return ApiResponse<bool>.Fail("请选择要删除的文件", 400);
                }

                var successCount = 0;
                var errors = new List<string>();

                foreach (var relativePath in relativePaths)
                {
                    var deleteResult = await DeleteFileAsync(relativePath);
                    if (deleteResult.Code == 200)
                    {
                        successCount++;
                    }
                    else
                    {
                        errors.Add($"{relativePath}: {deleteResult.Message}");
                    }
                }

                if (errors.Any())
                {
                    var message = $"成功删除 {successCount} 个文件，失败 {errors.Count} 个";
                    _logger.LogWarning(message);
                    return ApiResponse<bool>.Success(true, message);
                }

                return ApiResponse<bool>.Success(true, $"成功删除 {successCount} 个文件");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量删除文件失败");
                return ApiResponse<bool>.Fail("批量删除文件失败");
            }
        }

        /// <summary>
        /// 获取文件信息
        /// </summary>
        public async Task<ApiResponse<FileInfoDto>> GetFileInfoAsync(string relativePath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(relativePath))
                {
                    return ApiResponse<FileInfoDto>.Fail("文件路径不能为空", 400);
                }

                // 防止路径遍历攻击
                if (relativePath.Contains("..") || relativePath.Contains("~"))
                {
                    return ApiResponse<FileInfoDto>.Fail("无效的文件路径", 400);
                }

                var filePath = Path.Combine(_uploadRootPath, relativePath.Replace("/", "\\"));
                
                if (!File.Exists(filePath))
                {
                    return ApiResponse<FileInfoDto>.Fail("文件不存在", 404);
                }

                var fileInfo = await Task.Run(() => new FileInfo(filePath));
                
                var result = new FileInfoDto
                {
                    FileName = fileInfo.Name,
                    FileSize = fileInfo.Length,
                    FileSizeFormatted = FileHelper.FormatFileSize(fileInfo.Length),
                    Extension = fileInfo.Extension.ToLowerInvariant(),
                    IsImage = FileHelper.IsImage(fileInfo.Name),
                    CreateTime = fileInfo.CreationTime,
                    ModifyTime = fileInfo.LastWriteTime
                };

                return ApiResponse<FileInfoDto>.Success(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文件信息失败: {RelativePath}", relativePath);
                return ApiResponse<FileInfoDto>.Fail("获取文件信息失败");
            }
        }

        /// <summary>
        /// 获取文件流
        /// </summary>
        public async Task<(Stream? stream, string contentType, string fileName)> GetFileStreamAsync(string relativePath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(relativePath))
                {
                    return (null, string.Empty, string.Empty);
                }

                // 防止路径遍历攻击
                if (relativePath.Contains("..") || relativePath.Contains("~"))
                {
                    return (null, string.Empty, string.Empty);
                }

                var filePath = Path.Combine(_uploadRootPath, relativePath.Replace("/", "\\"));
                
                if (!File.Exists(filePath))
                {
                    return (null, string.Empty, string.Empty);
                }

                var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                var fileName = Path.GetFileName(filePath);
                var contentType = GetContentType(fileName);

                return await Task.FromResult((stream as Stream, contentType, fileName));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文件流失败: {RelativePath}", relativePath);
                return (null, string.Empty, string.Empty);
            }
        }

        #region 私有方法

        /// <summary>
        /// 验证文件
        /// </summary>
        private (bool success, string message) ValidateFile(IFormFile file)
        {
            if (file == null || file.Length == 0)
            {
                return (false, "文件不能为空");
            }

            if (file.Length > _maxFileSize)
            {
                return (false, $"文件大小超过限制 ({FileHelper.FormatFileSize(_maxFileSize)})");
            }

            if (!FileHelper.IsAllowedExtension(file.FileName))
            {
                return (false, $"不支持的文件类型: {Path.GetExtension(file.FileName)}");
            }

            return (true, string.Empty);
        }

        /// <summary>
        /// 获取Content-Type
        /// </summary>
        private static string GetContentType(string fileName)
        {
            var extension = Path.GetExtension(fileName).ToLowerInvariant();
            return extension switch
            {
                ".jpg" or ".jpeg" => "image/jpeg",
                ".png" => "image/png",
                ".gif" => "image/gif",
                ".bmp" => "image/bmp",
                ".webp" => "image/webp",
                ".svg" => "image/svg+xml",
                ".pdf" => "application/pdf",
                ".doc" => "application/msword",
                ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                ".xls" => "application/vnd.ms-excel",
                ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                ".ppt" => "application/vnd.ms-powerpoint",
                ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                ".txt" => "text/plain",
                ".zip" => "application/zip",
                ".rar" => "application/x-rar-compressed",
                ".7z" => "application/x-7z-compressed",
                ".mp4" => "video/mp4",
                ".mp3" => "audio/mpeg",
                _ => "application/octet-stream"
            };
        }

        #endregion
    }
}


